//Written in the D Programming Language
/*
 * Copyright (c) 2008 OpenGLUtils
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *
 * * Neither the name of 'OpenGLUtils' nor the names of its contributors 
 *   may be used to endorse or promote products derived from this software 
 *   without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
module testapps.TestApp;

import openglutils.GL;
import openglutils.GLU;
import openglutils.SDL;

import tango.stdc.stringz;

static this()
{
	if(SDL_Init(SDL_INIT_VIDEO) < 0)
	{
		throw new Exception("Failed to initialize SDL: " ~ getSDLError());
	}

	if((SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL)))
	{
		throw new Exception("Failed to set key repeat: " ~ getSDLError());
	}
}

static ~this()
{
	SDL_Quit();
}

public abstract class TestApp
{
	protected bool running = true;

	public void run()
	{
		while(running)
		{
			processEvents();

			drawGLScene();

			SDL_GL_SwapBuffers();
			SDL_Delay(10);
		}
	}

	public void createGLWindow(char[] title, int width, int height, int bits, bool fullScreen)
	{
		SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
		SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 6);
		SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
		SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
		SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);

		SDL_WM_SetCaption(toStringz(title), null);

		int mode = SDL_OPENGL;
		if(fullScreen)
		{
			mode |= SDL_FULLSCREEN;
		}

		if(SDL_SetVideoMode(width, height, bits, mode) is null)
		{
			throw new Exception("Failed to open OpenGL window: " ~ getSDLError());
		}

		DerelictGL.availableVersion();

		resizeGLScene(width, height);
	}

	protected abstract void drawGLScene();

	protected abstract void keyReleased(int key);

	protected abstract void keyPressed(int key);

	protected void initGL()
	{
		glEnable(GL_TEXTURE_2D);
		glShadeModel(GL_SMOOTH);
		glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
		glClearDepth(1.0f);
		glEnable(GL_DEPTH_TEST);
		glDepthFunc(GL_LEQUAL);
		glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
		glEnable(GL_LIGHT0);
		glEnable(GL_LIGHTING);
		glEnable(GL_COLOR_MATERIAL);

		glMatrixMode(GL_TEXTURE);
		glRotatef(180.0f, 0.0f, 0.0f, 1.0f);
		glScalef(-1.0f, 1.0f, 1.0f);
		glMatrixMode(GL_MODELVIEW);
	}

	private void resizeGLScene(GLsizei width, GLsizei height)
	{
		if(height == 0)
		{
			height = 1;
		}
		glViewport(0, 0, width, height);

		glMatrixMode(GL_PROJECTION);
		glLoadIdentity();

		gluPerspective(45.0f, cast(GLfloat) width / cast(GLfloat) height, 0.1f, 100.0f);

		glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();
	}

	private void processEvents()
	{
		SDL_Event event;
		while(SDL_PollEvent(&event))
		{
			switch(event.type)
			{
				case SDL_KEYUP:
					keyReleased(event.key.keysym.sym);
					break;
				case SDL_KEYDOWN:
					keyPressed(event.key.keysym.sym);
					break;
				case SDL_QUIT:
					running = false;
					break;
				default:
					break;
			}
		}
	}
}
